package com.example.opengldemo.jbulletJava;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3f;
import android.opengl.GLES30;
import android.util.Log;
import android.view.View;

import com.bulletphysics.collision.shapes.CollisionShape;
import com.bulletphysics.collision.shapes.TriangleIndexVertexArray;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.dynamics.constraintsolver.Point2PointConstraint;
import com.bulletphysics.extras.gimpact.GImpactMeshShape;
import com.bulletphysics.linearmath.Transform;
import com.example.opengldemo.util.MatrixState;
import com.example.opengldemo.util.ShaderManager;
import com.example.opengldemo.util.ShaderUtil;

public class LoadedObjectVertexNormal 
{
	int mProgram;
    int muMVPMatrixHandle;
    int muMMatrixHandle;
    int maCameraHandle;
    int maPositionHandle;
    int muColorHandle;
    int maNormalHandle;
    int maLightLocationHandle;
    
    String mVertexShader;
    String mFragmentShader;
	
	private FloatBuffer   mVertexBuffer;
    private FloatBuffer[]   mColorBuffer=new FloatBuffer[2];
    private FloatBuffer mNormalBuffer;
    int vCount=0;
    CollisionShape loadShape;
    float[] vertices;
    float[] normals;
	View mv;

	float midX;
	float midY;
	float midZ;
	RigidBody body;
    Point2PointConstraint p2p;  
    boolean isPicked=false;
    AABB3 preBox;
    float[] m = new float[16];
	float[] color= {0.33f,1,0.33f,1};
    public LoadedObjectVertexNormal(View mv, float[] vertices, float[] normals)
    {
    	this.mv=mv;
    	this.vertices=vertices;
    	this.normals=normals;
        vCount=vertices.length/3; 
        
    	preBox = new AABB3(vertices);
    	 
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
        vbb.order(ByteOrder.nativeOrder());
        mVertexBuffer = vbb.asFloatBuffer();
        mVertexBuffer.put(vertices);
        mVertexBuffer.position(0);
        
        float colors[]=new float[vCount*4];
        for(int i=0;i<vCount;i++)
        {
        	colors[i*4]=1;
        	colors[i*4+1]=0;
        	colors[i*4+2]=0;
        	colors[i*4+3]=1; 
        };
        
        ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
        cbb.order(ByteOrder.nativeOrder());
        mColorBuffer[0] = cbb.asFloatBuffer();
        mColorBuffer[0].put(colors);
        mColorBuffer[0].position(0);
        
        for(int i=0;i<vCount;i++)
        {
        	colors[i*4]=color[0]; 	
        	colors[i*4+1]=color[1]; 
        	colors[i*4+2]=color[2]; 
        	colors[i*4+3]=color[3]; 
        };
        cbb = ByteBuffer.allocateDirect(colors.length*4);
        cbb.order(ByteOrder.nativeOrder());
        mColorBuffer[1] = cbb.asFloatBuffer();
        mColorBuffer[1].put(colors);
        mColorBuffer[1].position(0);
        
        ByteBuffer nbb = ByteBuffer.allocateDirect(normals.length*4);
        nbb.order(ByteOrder.nativeOrder());
        mNormalBuffer = nbb.asFloatBuffer();
        mNormalBuffer.put(normals);
        mNormalBuffer.position(0);
        
    	ByteBuffer gVertices=ByteBuffer.allocateDirect(vCount*3*4).order(ByteOrder.nativeOrder());
    	for(int i=0;i<vertices.length;i++)
    	{
    		gVertices.putFloat(i*4,vertices[i]);
    	} 
    	gVertices.position(0);
    	ByteBuffer gIndices=ByteBuffer.allocateDirect(vCount*4).order(ByteOrder.nativeOrder());
    	for(int i=0;i<vCount;i++)
    	{
    		gIndices.putInt(i);
    	}
    	gIndices.position(0);

    	int vertStride = 4*3;
		int indexStride = 4*3;
    	TriangleIndexVertexArray indexVertexArrays= 
		new TriangleIndexVertexArray
		(
			vCount/3,
			gIndices,
			indexStride,
			vCount, 
			gVertices, 
			vertStride
		);
    	GImpactMeshShape trimesh = new GImpactMeshShape(indexVertexArrays);
    	trimesh.updateBound();
    	loadShape =trimesh;

		mVertexShader= ShaderUtil.loadFromAssetsFile("jbullet_java/vertex_color.sh", mv.getResources());
		mFragmentShader=ShaderUtil.loadFromAssetsFile("jbullet_java/frag_color.sh", mv.getResources());
		//mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
		mProgram  = ShaderManager.getObjectShaderProgram() ;
    	intShader();
    }
    

    public void intShader()
    {
		Log.e("intShader" , "mProgram > "+mProgram + " hashCode > "+this.hashCode()) ;
        maPositionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition");

        muMVPMatrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix");

        muMMatrixHandle = GLES30.glGetUniformLocation(mProgram, "uMMatrix"); 
        muColorHandle=GLES30.glGetUniformLocation(mProgram, "aColor");

        maNormalHandle= GLES30.glGetAttribLocation(mProgram, "aNormal");
         maLightLocationHandle=GLES30.glGetUniformLocation(mProgram, "uLightLocation");

        maCameraHandle=GLES30.glGetUniformLocation(mProgram, "uCamera");
    }

    public void drawSelf(RigidBody body) 
    {
		intShader() ;
    	this.body=body;
    	MatrixState.pushMatrix();
		Transform trans = body.getMotionState().getWorldTransform(new Transform());
		MatrixState.translate(trans.origin.x,trans.origin.y, trans.origin.z);
		Quat4f ro=trans.getRotation(new Quat4f());
		if(ro.x!=0||ro.y!=0||ro.z!=0)
		{
			float[] fa=SYSUtil.fromSYStoAXYZ(ro);
			if(!Float.isInfinite(fa[0])&&!Float.isInfinite(fa[1])&&!Float.isInfinite(fa[2])&&
					!Float.isNaN(fa[0])&&!Float.isNaN(fa[1])&&!Float.isNaN(fa[2])){
				MatrixState.rotate(fa[0],fa[1],fa[2],fa[3]);
			}
    	}
		
		copyM();
    	 GLES30.glUseProgram(mProgram);

         GLES30.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0);

         GLES30.glUniformMatrix4fv(muMMatrixHandle, 1, false, MatrixState.getMMatrix(), 0); 

         GLES30.glUniform3fv(maLightLocationHandle, 1, MatrixState.lightLocationFB);

         GLES30.glUniform3fv(maCameraHandle, 1, MatrixState.cameraLocationFB);
         GLES30.glUniform4fv(muColorHandle, 1, color, 0);
         GLES30.glVertexAttribPointer        
         (
         		maPositionHandle,   
         		3, 
         		GLES30.GL_FLOAT, 
         		false,
                3*4, 
                mVertexBuffer   
         );       

         GLES30.glVertexAttribPointer 
         (
        		maNormalHandle, 
         		3,   
         		GLES30.GL_FLOAT,
         		false,
                3*4,   
                mNormalBuffer
         );

         GLES30.glEnableVertexAttribArray(maPositionHandle);  
         GLES30.glEnableVertexAttribArray(maNormalHandle);  
           

         GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vCount); 
         MatrixState.popMatrix();
    }
    
    public LoadedObjectVertexNormal clone(){
    	return new LoadedObjectVertexNormal(mv,vertices,normals); 
    }
    

    public void changeColor(boolean flag)
    {
    	if(body!=null && !body.isActive()&&!isPicked){
    		color=new float[]
    		{
    			0,1,1,1
    		};  
    	}else{
    		if(flag){
        		color=new float[]{
        			0,1,0,1
        		};
        	}
        	else{
        		color=new float[]{
        			1,1,1,1
        		};
        	}
    	}
    }
    public void addPickedConstraint(){

    	p2p = new Point2PointConstraint(body, new Vector3f(0,0,0));
		((MySurfaceView7)mv).dynamicsWorld.addConstraint(p2p, true);
    	this.isPicked=true;
    	
    }
    public void removePickedConstraint(){    	
    	if(p2p!=null){
			((MySurfaceView7)mv).dynamicsWorld.removeConstraint(p2p);
    	}
    	this.isPicked=false;
    }

    public AABB3 getCurrBox(){
    	return preBox.setToTransformedBox(m);
    
    }

    public void copyM(){
    	for(int i=0;i<16;i++){
    		m[i]=MatrixState.getMMatrix()[i];
    	}
    }
}
